//文件名：SYS_vehicleOTA
//功能：整车升级
//创建时间：2022年12月29日
//作者：dowson
//email：dowson.tseng@gmail.com
#include "system_init.h"
// #include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "SYS_OTAUpgrade.h"
#include "APP_vehicleOTA.h"
#include "4G-HTTP_open_GPS.h"
#include "CanIf.h"
#include "at32f403a_407_board.h"
#include "Mqtt4GDriver.h"
#define OTA_LOG 1
t_downloadFileParam downloadFileParam;

t_fileDownloadListHead fileDownloadListHead;

//整车OTA初始化函数
void AppVehicleOTAInit(void){
    downloadFileParam.downloadState = FILE_NONE;
    downloadFileParam.fileIndex = 0xff;
    downloadFileParam.downloadedLen = 0;
    downloadFileParam.downloadURL = NULL;
    downloadFileParam.urlLen = 0;
    memset(downloadFileParam.fileName,0x00,sizeof(downloadFileParam.fileName));

    downloadFileParam.fileDownloadListHead = &fileDownloadListHead;
}

int Wireless_Receive_BackBuff;

//下载OTA数据到目标文件任务函数
//输入：void
//返回: void
void Download4GDataToFile(void){
    static uint8_t funcStep = 0;
    static uint8_t chackTimes = 0;
    static uint32_t filePtr4G = 0;
    static uint8_t getData0ErrorTimes = 0;
    static uint16_t transfer_times=0;
    uint8_t binData[2048];
    uint16_t downloadLength = 1024,getDataLength = 0;
    static uint32_t getDataLengthSum = 0;
    tTaskItem *thisTask;
    uint16_t reciveFileSize = 0;
    uint8_t fileIndex = 0;
    tFileHead fileHead;	
    uint8_t httpConfigCmd[64];

    extern uint16_t uart0_rx_count;

    thisTask = FindRunnningItem();
    switch (funcStep)
    {
    case THIRD_STEP0:
        if(downloadFileParam.downloadState == FILE_REQUEST){
            //默认已经进入升级模式，及屏蔽CAN，GPS等信息
            //设置不上报信息头
            memset(httpConfigCmd,0x00,sizeof(httpConfigCmd));
            strcat((char*)httpConfigCmd,"AT+ZHTTPCFG=responseheader,0\r\n");
            // USART2_SendMore(httpConfigCmd,strlen(httpConfigCmd));
	        // USART0_SendMore(httpConfigCmd,strlen(httpConfigCmd));
            funcStep = THIRD_STEP1;
        }else{
            //没有请求直接退出任务
            funcStep = THIRD_STEP0;
            TaskToClosed(thisTask);
        }
        break;
    case THIRD_STEP1:
        //设置Http请求
        Wirelesess_ReceiveBuff_Eliminate(); //清空数据缓冲区值
#if OTA_LOG
        fprintf(USART2_STREAM,"send url:%s\n",downloadFileParam.downloadURL);	
#endif	
        HTTP_Link_CMD(downloadFileParam.downloadURL,downloadFileParam.urlLen);
		funcStep = THIRD_STEP2;
		GOToSleep(TASK_AT_WAIT);
        break;
    case THIRD_STEP2:
        Wirelesess_Common_Receive();
		if (Wireless_Receive_BackBuff){
             //设置成功
			Wirelesess_ReceiveBuff_Eliminate(); 
#if OTA_LOG
			fprintf(USART2_STREAM,"set url ok\n"); 
#endif
			//设置数据存储文件名
			HTTP_StorageData_CMD(downloadFileParam.fileName,strlen((const char*)(downloadFileParam.fileName)));
			funcStep = THIRD_STEP3;
			GOToSleep(TASK_AT_WAIT);
		}else{
#if OTA_LOG
			fprintf(USART2_STREAM,"set url failed\n");
#endif
			funcStep = THIRD_STEP1;
			//通知服务器升级失败
		}
        break;
    case THIRD_STEP3:
		Wirelesess_Common_Receive();
		if (Wireless_Receive_BackBuff){
             //设置成功
			Wirelesess_ReceiveBuff_Eliminate(); 
#if OTA_LOG
			fprintf(USART2_STREAM,"set save name ok\n");
#endif
			//开始让4G模块自动下载数据
			HTTP_DataRequest_CMD();
			funcStep = THIRD_STEP4;
			chackTimes = 0;
			//下载文件
			SysDelay(500);
			
		}else{
#if OTA_LOG
			fprintf(USART2_STREAM,"cant set save name\n");
#endif
			funcStep = THIRD_STEP1;
			//通知服务器升级失败
		}        
        break;
    case THIRD_STEP4:
		fprintf(USART2_STREAM,"check bin size\n");
		Wirelesess_ReceiveBuff_Eliminate(); 
		FILE_Inquire_CMD(downloadFileParam.fileName,strlen((const char*)(downloadFileParam.fileName)));
		funcStep = THIRD_STEP5;
		GOToSleep(TASK_AT_WAIT);

        if(chackTimes>10){ 
            chackTimes =0;
            //关闭该线程
            fprintf(USART2_STREAM,"ota THIRD_STEP4 error\n");
            funcStep =THIRD_STEP0;
			downloadFileParam.downloadState = FILE_ERROR;
			SetSysNeedOnlineState(true);
			SetSysRunState(SYS_NORMAL);  //切换回去避免跑空
			OpenInterupt_CAN();
            TaskToClosed(thisTask);
        }else chackTimes++;        
        break;
    case THIRD_STEP5:
		reciveFileSize = checkFileSize(wireless_rxbuff,downloadFileParam.fileName,strlen((const char*)(downloadFileParam.fileName)));
		fprintf(USART2_STREAM,"get recv len:%d,file len:%d\n",reciveFileSize,downloadFileParam.targetFileLen);

		if(reciveFileSize == downloadFileParam.targetFileLen){
			//文件接收完成，开始传输到外部flash
			fprintf(USART2_STREAM,"check file name:%s\n",downloadFileParam.fileName);
			fileIndex = CheckFileName(downloadFileParam.fileName);
			if(fileIndex == 0xff){
				fprintf(USART2_STREAM,"no ota file creat\n");
				fileIndex = CreatFileHandle(downloadFileParam.fileName,0);
			}
			Wirelesess_ReceiveBuff_Eliminate(); 
			fprintf(USART2_STREAM,"file download complete\n");
			funcStep = THIRD_STEP6;
		}else{
			funcStep = THIRD_STEP4;
			//OTA_Request.fileSize = OTA_Request.reciveFileSize;

			SysDelay(100);
		}
        break;   
        case  THIRD_STEP6:
            //发送请求数据
            Wirelesess_ReceiveBuff_Eliminate(); 
            FILE_Download_CMD(downloadFileParam.fileName,strlen((const char*)(downloadFileParam.fileName)),getDataLengthSum,downloadLength);
    #if OTA_LOG
            fprintf(USART2_STREAM,"send request again\n");
    #endif
            funcStep = THIRD_STEP7;
            GOToSleep(TASK_AT_WAIT);
        break;
        case THIRD_STEP7:

			// getDataLength = HttpExtractionDownloadData(binData,wireless_rxbuff,uart0_rx_count);   // need to be uncomment
            if(getDataLength<=downloadLength){
                getDataLengthSum+=getDataLength;
            }
#if OTA_LOG
			fprintf(USART2_STREAM,"get transfrom file len:%d,filePtr4G:%d,times:%d\n",getDataLength,filePtr4G,transfer_times);
#endif
			if(getDataLength > 0 &&getDataLength <= downloadLength){
				
				//打开本地文件并保存
				fileHead = OpenFile(fileIndex);
				// fprintf(USART2_STREAM,"source data:\r\n");
				// for(i=0;i<getDataLength;i++)
				// 	fprintf(USART2_STREAM,"%x|",binData[i]);
				// fprintf(USART2_STREAM,"\r\n");
				WriteToFile_New(&fileHead,binData,getDataLength);
				CloseFile(fileIndex,&fileHead);
				fprintf(USART2_STREAM,"save to flash,ptr:%d\n",fileHead.writePtr);
			}
			if(getDataLength == 0){
				getData0ErrorTimes++;
				if(getData0ErrorTimes >20){
					fprintf(USART2_STREAM,"0 len times >20 error\n");
					//连续获得数据长度为0,升级失败
					DeleteFile(fileIndex);
					downloadFileParam.errorCode = 0x02;	
					funcStep = THIRD_STEP8;
					transfer_times = 0;	
					break;			
				}
			}else{
				getData0ErrorTimes = 0;
			}
			fprintf(USART2_STREAM,"downloadLength:%d,getDataLength:%d\n",downloadLength,downloadFileParam.targetFileLen);

            if(getDataLengthSum == downloadFileParam.targetFileLen){

                fprintf(USART2_STREAM,"get file complete:%d,targetlen:%d\n",getDataLengthSum,downloadFileParam.targetFileLen);
                downloadFileParam.downloadState = FILE_DLOADED;
                funcStep = THIRD_STEP8;
                transfer_times = 0;
            }else{
				//未接收完成继续发送
				funcStep = THIRD_STEP6;
				SysDelay(50); //考虑发送太快4g模块帧头丢失，延迟1秒继续请求数据
            }
			transfer_times ++;
			Wirelesess_ReceiveBuff_Eliminate(); 
        break;

        case THIRD_STEP8:
            fprintf(USART2_STREAM,"move ota file complete\n");
            downloadFileParam.downloadState = FILE_DLOADED;

            //删除4G缓存文件
            FILE_Delete_CMD(downloadFileParam.fileName,strlen((const char*)(downloadFileParam.fileName)));
            SaveFileAll();

            TaskToClosed(thisTask);
        break;
    default:
        break;
    }

}

//下载OTA升级文件
uint8_t DownloadOTAFile(tOTA_Request l_OTA_Request){
    // tTaskItem *thisTask;
    t_fileDownloadListHead *fileDownloadListHead;
    static uint8_t currentNodeList=0;
    fileDownloadListHead = downloadFileParam.fileDownloadListHead;
    //TODO:
    //循环创建下载连接
    if(fileDownloadListHead->nodeSize && (downloadFileParam.downloadState == FILE_NONE) && (1==ThirdHasBeenCreat(Download4GDataToFile))){
        fileDownloadListHead->nodeSize --;
        //创建文件下载任务
        downloadFileParam.downloadState = FILE_REQUEST;
        downloadFileParam.urlLen = fileDownloadListHead->FileDownloadList[currentNodeList].downloadUrlLength;
        downloadFileParam.downloadURL=fileDownloadListHead->FileDownloadList[currentNodeList].downloadUrl;
        
        memcpy(downloadFileParam.fileName,l_OTA_Request.fileName,sizeof(downloadFileParam.fileName));
        downloadFileParam.targetFileLen = fileDownloadListHead->FileDownloadList[currentNodeList].fileLength;
        fprintf(USART2_STREAM,"set file param:\n");
        fprintf(USART2_STREAM,"downloadFileParam.downloadState:%d\n",downloadFileParam.downloadState);
        fprintf(USART2_STREAM,"downloadFileParam.downloadedLen:%d\n",downloadFileParam.downloadedLen);
        fprintf(USART2_STREAM,"downloadFileParam.targetFileLen:%d\n",downloadFileParam.targetFileLen);
        fprintf(USART2_STREAM,"downloadFileParam.downloadURL:%s\n",downloadFileParam.downloadURL);
        currentNodeList ++;
        CreatThird("download",To_OS_Slice_Time(100,OS_MSEC),10,Download4GDataToFile);
    }
    return downloadFileParam.downloadState;
}

//下载OTA升级驱动文件
uint8_t DownloadDriverFile(tOTA_Request l_OTA_Request){
    extern tOTA_Request OTA_Request;
    // tTaskItem *thisTask;
    t_fileDownloadListHead *fileDownloadListHead;
    static uint8_t currentNodeList=0;

    fileDownloadListHead = downloadFileParam.fileDownloadListHead;
    //TODO:
    //循环创建下载连接
    //fprintf(USART2_STREAM,"start driver download task:%d,%d\n",fileDownloadListHead->driverNodeSize,downloadFileParam.downloadState);   
    if(fileDownloadListHead->driverNodeSize && (downloadFileParam.downloadState == FILE_NONE) && (1==ThirdHasBeenCreat(Download4GDataToFile))){
        fprintf(USART2_STREAM,"creat driver download task");
        fileDownloadListHead->driverNodeSize --;
        //创建文件下载任务
        downloadFileParam.downloadState = FILE_REQUEST;
        downloadFileParam.urlLen = fileDownloadListHead->FileDownloadDriverList[currentNodeList].downloadUrlLength;
        downloadFileParam.downloadURL=fileDownloadListHead->FileDownloadDriverList[currentNodeList].downloadUrl;
        
        memcpy(downloadFileParam.fileName,l_OTA_Request.driverFileName,sizeof(downloadFileParam.fileName));
        downloadFileParam.targetFileLen = fileDownloadListHead->FileDownloadDriverList[currentNodeList].fileLength;
        fprintf(USART2_STREAM,"set driver file param:\n");
        fprintf(USART2_STREAM,"downloadFileParam.downloadState:%d\n",downloadFileParam.downloadState);
        fprintf(USART2_STREAM,"downloadFileParam.downloadedLen:%d\n",downloadFileParam.downloadedLen);
        fprintf(USART2_STREAM,"downloadFileParam.targetFileLen:%d\n",downloadFileParam.targetFileLen);
        fprintf(USART2_STREAM,"fileDownloadListHead->FileDownloadDriverList[currentNodeList].downloadUrl:%s\n",fileDownloadListHead->FileDownloadDriverList[currentNodeList].downloadUrl);
        fprintf(USART2_STREAM,"downloadFileParam.downloadURL:%s\n",downloadFileParam.downloadURL);
        currentNodeList ++;
        OTA_Request.needDriverFile = false;
        CreatThird("download",To_OS_Slice_Time(100,OS_MSEC),10,Download4GDataToFile);
    }
    // if(!l_OTA_Request.fileSize){
    //     //下载完成
    //     return FILE_DLOADED;
    // }
    return downloadFileParam.downloadState;       
}

//整车升级主程序
void VehicleOTAMainLoop(void){
    extern tOTA_Request OTA_Request;
    static uint8_t funcStep = 0;
    tTaskItem *thisTask;
    //fprintf(USART2_STREAM,"in ota main loop\n");   
    switch (funcStep)
    {
    case THIRD_STEP0:
        //进入升级模式，关闭可能影响的功能
            //屏蔽CAN中断，开始准备升级（GPS上传等在进入升级模式启动该任务时已经开始）
        InUpgradeMode();
        //判断升级方法，强制升级或者普通升级
        //memset(OTA_Request.fileName,0x00,sizeof(OTA_Request.fileName));
        switch (OTA_Request.otaDevice)
        {
        case DEV_TBOX:
            break;
        case DEV_BMS:
            break;
        case DEV_MCU:
            break;
        default:
            fprintf(USART2_STREAM,"unknow ota dev:%d\n",OTA_Request.otaDevice);   
            break;
        }
        
        fprintf(USART2_STREAM,"ota mark:%d,dev:%d,name:%s\n",OTA_Request.otaMark,OTA_Request.otaDevice,OTA_Request.fileName);   
        
        switch (OTA_Request.otaMark)
        {
        case 0x01:
        //强制下载强制升级
            //立即将系统强制转化为升级模式
            SetSysRunState(SYS_UPGRADE);
            //Wirelesess_GPS_open_off(0);
            // GPT_CMPL
            // GPTIM_Set_Period(T4_SFR,4000);	 //4G模块某些下载帧间隔超过2ms,重新设置接收完成定时器时间为4ms。【必须】
            //删除已有的4G文件
            FILE_Delete_CMD(OTA_Request.fileName,strlen((const char*)(OTA_Request.fileName)));
            delay_ms(20);
            FILE_Delete_CMD(OTA_Request.driverFileName,strlen((const char*)(OTA_Request.driverFileName)));
            //休眠5秒后开始升级，目的是等待系统进入升级模式（关闭其他任务）
            SysDelay(300);
            fprintf(USART2_STREAM,"start device ota\n");	
            funcStep = THIRD_STEP1;	
            break;
        // case 0x02:
        // //强制下载非强制升级
        // 	break;
        // case 0x03:
        // //非强制下载非强制升级
        // 	break;
        // case 0x04:
        // //本地版本回退
        // 	break;
        default:
            fprintf(USART2_STREAM,"unknow ota mark:%d\n",OTA_Request.otaMark);   
            break;
        }
    break;
    case THIRD_STEP1:
        //判断是否需要下载驱动文件
        //fprintf(USART2_STREAM,"need download driver?:%d\n",OTA_Request.needDriverFile);   
        if(OTA_Request.needDriverFile){
            //启动下载驱动任务
            downloadFileParam.downloadState = FILE_NONE;
            DownloadDriverFile(OTA_Request);
        }
        fprintf(USART2_STREAM,"download driver end?:%d,%d\n",downloadFileParam.downloadState,downloadFileParam.fileDownloadListHead->driverNodeSize);   
        if(downloadFileParam.downloadState == FILE_DLOADED && downloadFileParam.fileDownloadListHead->driverNodeSize==0){
            //funcStep = THIRD_STEP2;	
            //测试直接跳过主文件
            funcStep = THIRD_STEP3;	
            fprintf(USART2_STREAM,"download driver end\r\n");
            downloadFileParam.downloadState = FILE_NONE;
        }
    break;
    case THIRD_STEP2:
        //下载主程序
        fprintf(USART2_STREAM,"download ota file\n");   
        DownloadOTAFile(OTA_Request);
        if(downloadFileParam.downloadState == FILE_DLOADED){
            funcStep = THIRD_STEP3;	
            downloadFileParam.downloadState = FILE_NONE;
        }
    break;
    case THIRD_STEP3:
        //判断升级零部件类型，设置标志
        //如果是非自身OTA则开启CAN升级逻辑
        if(OTA_Request.otaDevice == DEV_TBOX){
            SetUpgradeMark(UPGRADE_OTA);
            
        }else{
            //其他设备升级启动升级功能
        }
        OutUpgradeMode();
        TaskToClosed(thisTask);
    break;
    }
}

//进入升级模式函数
void InUpgradeMode(void){
    CloseInterupt_CAN();
}

//退出升级模式函数
void OutUpgradeMode(void){
    //退出升级模式
    SetSysNeedOnlineState(true);
#ifdef GPT_CMPL
    GPTIM_Set_Period(T4_SFR, 2000);         // TODO raoy 是否需要更新定时器周期值
#endif
    // 打开CAN中断
    Can_EnableControllerInterrupts(CanController_Can0);
    Wirelesess_GPS_open_off(2);
    delay_ms(10);
    OpenInterupt_CAN();
}

//注册文件下载请求
//输入：文件请求结构体
//返回：0 注册成功，其它 错误
uint8_t RegisterFileDownload(t_downloadFileParam downloadParam){
    downloadFileParam = downloadParam;
    return 0;
}

//查下文件下载状态
eFileDownloadState checkFileDownloadState(void){
    return (eFileDownloadState)0; //return downloadFileParam.downloadState;
}

//功能测试函数
void TestFunc(void){
    extern tOTA_Request OTA_Request;
    t_fileDownloadListHead *fileDownloadListHead;

    uint8_t *url1 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/BMS1.S19";
    uint8_t *url2 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/BMS2.S19";
    uint8_t *url3 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/BMS3.S19";
    uint8_t *url4 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/BMS4.S19";
    uint8_t *url5 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/BMS5.S19";
    uint8_t *url6 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/BMS6.S19";
    uint8_t *url7 = "https://dev-jz-pri.oss-cn-hangzhou.aliyuncs.com/template/driver.s19";

    AppVehicleOTAInit();
    //制作假数据
    memcpy(OTA_Request.driverFileName,"drive",strlen("drive"));
    OTA_Request.driverFileSize = 100;
    memcpy(OTA_Request.fileName,"bms",strlen("bms"));
    OTA_Request.fileParts = 8;
    OTA_Request.otaDevice = DEV_BMS;
    OTA_Request.needDriverFile = true;
    OTA_Request.updateMode = 1;
    OTA_Request.otaMark = 1;

    fileDownloadListHead = downloadFileParam.fileDownloadListHead;
    fileDownloadListHead->nodeSize = 7;

    fileDownloadListHead->driverNodeSize = 1;
    fprintf(USART2_STREAM,"***driver:%d,file:%d***\n",downloadFileParam.fileDownloadListHead->driverNodeSize,downloadFileParam.fileDownloadListHead->nodeSize);  

    fileDownloadListHead->FileDownloadDriverList[0].fileLength = 3844;
    fileDownloadListHead->FileDownloadDriverList[0].filePtrNum = 1;
    fileDownloadListHead->FileDownloadDriverList[0].downloadUrlLength = strlen((const char*)url7);
    memcpy(fileDownloadListHead->FileDownloadDriverList[0].downloadUrl,url7,strlen((const char*)url7));    
    fprintf(USART2_STREAM,"***driver url:%s\n",downloadFileParam.fileDownloadListHead->FileDownloadDriverList[0].downloadUrl);

    fileDownloadListHead->FileDownloadList[0].fileLength = 115005;
    fileDownloadListHead->FileDownloadList[0].filePtrNum = 1;
    fileDownloadListHead->FileDownloadList[0].downloadUrlLength = strlen((const char*)url1);
    memcpy(fileDownloadListHead->FileDownloadList[0].downloadUrl,url1,strlen((const char*)url1));

    fileDownloadListHead->FileDownloadList[1].fileLength = 115005;
    fileDownloadListHead->FileDownloadList[1].filePtrNum = 2;
    fileDownloadListHead->FileDownloadList[1].downloadUrlLength = strlen((const char*)url2);
    memcpy(fileDownloadListHead->FileDownloadList[0].downloadUrl,url2,strlen((const char*)url2));

    fileDownloadListHead->FileDownloadList[2].fileLength = 115005;
    fileDownloadListHead->FileDownloadList[2].filePtrNum = 3;
    fileDownloadListHead->FileDownloadList[2].downloadUrlLength = strlen((const char*)url3);
    memcpy(fileDownloadListHead->FileDownloadList[0].downloadUrl,url3,strlen((const char*)url3));

    fileDownloadListHead->FileDownloadList[3].fileLength = 115005;
    fileDownloadListHead->FileDownloadList[3].filePtrNum = 4;
    fileDownloadListHead->FileDownloadList[3].downloadUrlLength = strlen((const char*)url4);
    memcpy(fileDownloadListHead->FileDownloadList[3].downloadUrl,url4,strlen((const char*)url4));

    fileDownloadListHead->FileDownloadList[4].fileLength = 115005;
    fileDownloadListHead->FileDownloadList[4].filePtrNum = 5;
    fileDownloadListHead->FileDownloadList[4].downloadUrlLength = strlen((const char*)url5);
    memcpy(fileDownloadListHead->FileDownloadList[4].downloadUrl,url5,strlen((const char*)url5));

    fileDownloadListHead->FileDownloadList[5].fileLength = 106025;
    fileDownloadListHead->FileDownloadList[5].filePtrNum = 6;
    fileDownloadListHead->FileDownloadList[5].downloadUrlLength = strlen((const char*)url6);
    memcpy(fileDownloadListHead->FileDownloadList[5].downloadUrl,url6,strlen((const char*)url6));

    fprintf(USART2_STREAM,"***begin ota function tset***\n");  
    fprintf(USART2_STREAM,"***driver:%d,file:%d***\n",downloadFileParam.fileDownloadListHead->driverNodeSize,downloadFileParam.fileDownloadListHead->nodeSize);  

    //启动OTA主函数
    fprintf(USART2_STREAM,"start ota function\n");   
    CreatThird("vOta",To_OS_Slice_Time(100,OS_MSEC),10,VehicleOTAMainLoop);
    //fprintf(USART2_STREAM,"ota end test\n");   
}















